/*
 * ControladorR16Consumidor.h
 *
 *  Created on: Dec 1, 2013
 *      Author: m
 */

#ifndef CONTROLADORR16CONSUMIDOR_H_
#define CONTROLADORR16CONSUMIDOR_H_

#include "ICinta15.h"
#include "IRobot14.h"
#include "IRobot16.h"

#include "Cinta15.h"
#include "Robot14Productor.h"
#include "Robot16Consumidor.h"
#include "DSMManager.h"

class ControladorR16Consumidor :
        public ICinta15, public IRobot14, public IRobot16
{
protected:
    Cinta15 m_cinta15;
    Robot14Productor  m_robot14;
    Robot16Consumidor m_robot16;

    bool m_primerAvanceCinta15;

    void tomarCinta15()
    {
        // Si el productor esta usando la cinta espero a que termine
        if ( m_cinta15.getCinta()->productorUsando() )
        {
            m_cinta15.getCinta()->setConsumidorEsperando( true );

            m_cinta15.terminarExclusionMutua();

            m_cinta15.dormirConsumidor();

            m_cinta15.iniciarExclusionMutua();
        }
        else
        {
            m_cinta15.getCinta()->setConsumidorUsando( true );
        }
    }

    void liberarCinta15()
    {
        m_cinta15.getCinta()->setConsumidorUsando( false );

        if ( m_cinta15.getCinta()->productorEsperando() )
        {
            m_cinta15.getCinta()->setProductorEsperando( false );

            m_cinta15.getCinta()->setProductorUsando( true );

            m_cinta15.despertarProductor();
        }
    }

public:
    ControladorR16Consumidor() :
            m_primerAvanceCinta15( true )
    {
    	DSMManager::inicializar("robot16");
    }

    virtual ~ControladorR16Consumidor()
    {
    }

    bool c15_tieneElementos()
    {
        bool tieneElementos;

        m_primerAvanceCinta15 = true;

        m_cinta15.iniciarExclusionMutua();

        this->tomarCinta15();

        tieneElementos = m_cinta15.getCinta()->tieneElementos();

        m_cinta15.terminarExclusionMutua();

        return tieneElementos;
    }

    bool c15_avanzar()
    {
        bool avanzoOk;

        m_cinta15.iniciarExclusionMutua();

        // Si es la primera vez que avanza, toma la cinta
        if ( m_primerAvanceCinta15 )
        {
            m_primerAvanceCinta15 = false;

            this->tomarCinta15();
        }

        avanzoOk = m_cinta15.getCinta()->avanzar();

        m_cinta15.terminarExclusionMutua();

        return avanzoOk;
    }

    ElementoProduccion c15_quitar()
    {
        ElementoProduccion elem;

        m_cinta15.iniciarExclusionMutua();

        elem = m_cinta15.getCinta()->quitar();

        m_cinta15.terminarExclusionMutua();

        return elem;
    }

    bool r14_esperaEspacioVacio()
    {
        bool esperaEspacioVacio;

        m_robot14.iniciarExclusionMutua();
        esperaEspacioVacio = m_robot14.esperaEspacio();
        m_robot14.terminarExclusionMutua();

        return esperaEspacioVacio;
    }

    void r14_notificarEspacioVacio()
    {
        m_cinta15.iniciarExclusionMutua();

        m_robot14.iniciarExclusionMutua();
        m_robot14.setEsperaEspacio( false );
        m_robot14.despertar();
        m_robot14.terminarExclusionMutua();

        m_cinta15.getCinta()->setConsumidorUsando( false );
        m_cinta15.getCinta()->setConsumidorEsperando( true );

        m_cinta15.despertarProductor();

        m_cinta15.terminarExclusionMutua();

        m_cinta15.dormirConsumidor();
    }

    void r14_notificarQuiteElemento()
    {
        m_cinta15.iniciarExclusionMutua();
        m_robot14.iniciarExclusionMutua();

        if ( m_robot14.esperaEspacio() )
        {
            m_robot14.setEsperaEspacio( false );
            m_robot14.despertar();
            m_cinta15.getCinta()->setProductorEsperando( true );
        }

        m_robot14.terminarExclusionMutua();

        // Libera la cinta 15
        this->liberarCinta15();
        m_cinta15.terminarExclusionMutua();
    }

    void r16_esperarNuevoElemento()
    {
        // Actualiza el estado de R14
        m_robot16.iniciarExclusionMutua();
        m_robot16.setEsperaProducto( true );
        m_robot16.terminarExclusionMutua();

        // Libera la cinta
        m_cinta15.iniciarExclusionMutua();
        this->liberarCinta15();
        m_cinta15.terminarExclusionMutua();

        // Espera en el semaforo correspondiente
        m_robot16.dormir();

        // toma nuevamente la cinta
        m_cinta15.iniciarExclusionMutua();
        this->tomarCinta15();
        m_cinta15.terminarExclusionMutua();
    }



    int c15_contarElementos()
    {
        throw Exception("Metodo no implementado");
    }

    bool c15_depositar( const ElementoProduccion &e )
    {
        throw Exception("Metodo no implementado");
    }

    void r14_esperarEspacioVacio()
    {
        throw Exception("Metodo no implementado");
    }

    void r14_notificarNuevoElemento()
    {
        throw Exception("Metodo no implementado");
    }

    void r14_esperarNuevoElemento()
    {
        throw Exception("Metodo no implementado");
    }

    void r16_notificarNuevoElemento()
    {
        throw Exception("Metodo no implementado");
    }

    bool r16_esperaNuevoElemento()
    {
        throw Exception("Metodo no implementado");
    }

};

#endif /* CONTROLADORR16CONSUMIDOR_H_ */
